/*
 * Algorithms.h
 *
 *  Created on: 03.11.2011
 *	  Author: pavel
 */

/*
Definitions
obs - observation
n - number of states
m - size of alphabet
pi - initial probabilities of states
a - transition probability matrix
b - emission probabilies
*/

#ifndef ALGORITHMS_H_
#define ALGORITHMS_H_

#include <vector>


typedef std::vector<unsigned> Observation;

namespace HMMALG {

	double probOfObservationOnModel(const Observation &obs, unsigned n, unsigned m,
										 const std::vector<double> &pi,
										 const std::vector<std::vector<double> > &a,
										 const std::vector<std::vector<double> > &b);
	/**
	 * Calculate the logarithm of P(obs| model) using foraward-bacward algorithm.
	 * P(obs| model) - probability of fact that the observation 'obs' was generated by model(n, m, pi, a, b).
	 */
	double logProbOfObservationOnModel(const Observation &obs, const unsigned n, const unsigned m,
								const std::vector<double> &pi,
								const std::vector<std::vector<double> > &a,
								const std::vector<std::vector<double> > &b, double eps = 0);

	/**
	 * Calculate the logarithm probability by norming factors 'normfactors'.
	 */
	double logProb(const std::vector<double> &normfactors);

	void calculateScaledAlpha(const Observation &obs, unsigned n, unsigned m,
			const std::vector<double> &pi,
			const std::vector<std::vector<double> > &a,
			const std::vector<std::vector<double> > &b,
			std::vector<std::vector<double> > &scaled_alpha,
			std::vector<double>& normfactors);

	void calculateScaledAlpha(const Observation &obs, unsigned n, unsigned m,
			const std::vector<double> &pi,
			const std::vector<std::vector<double> > &a,
			const std::vector<std::vector<double> > &b,
			std::vector<std::vector<double> > &scaled_alpha);

	void calculateScaledBeta(const Observation &obs, unsigned n, unsigned m,
			const std::vector<double> &pi,
			const std::vector<std::vector<double> > &a,
			const std::vector<std::vector<double> > &b,
			std::vector<std::vector<double> > &scaled_beta);

	void calculateGamma(const std::vector<std::vector<double> > &scaled_alpha,
									const std::vector<std::vector<double> > &scaled_beta,
									std::vector<std::vector<double> > &scaled_gamma);

	double normalize(std::vector<double> &v);
	
	double normalize(std::vector<double> &v, double eps);

	double normalize(double* v, unsigned n);

	void printVector(const std::vector<double> &v);
	
	void printIntRow(const std::vector<int> &v);
	
	void printUnsignedRow(const std::vector<unsigned> &v);

	void printMatrix(const std::vector<std::vector<double> > &v);

	void printMatrix(double **m, unsigned rows, unsigned cols);

	double sumArray(double* v, unsigned size);

	double sumVector(const std::vector<double> &v);
	int sumVector(const std::vector<int> &v);
	unsigned sumVector(const std::vector<unsigned> &v);

	void generate(Observation &obs, unsigned n, unsigned m,
						const std::vector<double> &pi,
						const std::vector<std::vector<double> > &a,
						const std::vector<std::vector<double> > &b);

	double random();

	int select(const std::vector<double> &probs, double treshold);
	
	double average(const std::vector<int> &v);
	
	double dispersion(const std::vector<int> &v);
	
	double average(const Observation &v);
	
	double dispersion(const Observation &v);

	void histogram(const std::vector<int> &v, int &min, int &max,
				   std::vector<double> &histogram);


	void histogram(const Observation &v, unsigned &min, unsigned &max,
				   std::vector<double> &histogram);

	void findMostProbablePath(const Observation &obs, unsigned n, unsigned m,
										 const std::vector<double> &pi,
										 const std::vector<std::vector<double> > &a,
										 const std::vector<std::vector<double> > &b,
										 std::vector<unsigned> &path);
	
	void fill(std::vector<double> array, double value);
	void fill(std::vector<std::vector<double> > array, double value);
	
} //namespace HMMALG


#endif /* ALGORITHMS_H_ */
